package com.hongyun.tms.web.controller;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.hongyun.tms.common.PageResponseDto;
import com.hongyun.tms.common.annotation.RepeatSubmit;
import com.hongyun.tms.common.constants.ProdPlanStatusConstant;
import com.hongyun.tms.common.dto.pordwork.PordWorkExportDto;
import com.hongyun.tms.common.dto.prodplan.*;
import com.hongyun.tms.common.enums.DictTypeEnum;
import com.hongyun.tms.common.enums.ProdPlanEnum;
import com.hongyun.tms.common.enums.RateTradeTypeEnum;
import com.hongyun.tms.common.utils.DateUtils;
import com.hongyun.tms.common.vo.ProPlanVO;
import com.hongyun.tms.domain.AjaxResult;
import com.hongyun.tms.entity.PordWork;
import com.hongyun.tms.entity.ProdPlan;
import com.hongyun.tms.infra.excel.StyleUtils;
import com.hongyun.tms.infra.excel.config.CustomCellWriteHeightConfig;
import com.hongyun.tms.infra.excel.config.CustomCellWriteWidthConfig;
import com.hongyun.tms.service.IPordWorkService;
import com.hongyun.tms.service.IProdPlanService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 作业计划 前端控制器
 * </p>
 *
 * @author liPeng
 * @since 2024-06-12
 */
@Api(tags = "作业计划管理")
@RestController
@RequestMapping("/prodPlan")
public class ProdPlanController {
    @Resource
    private IProdPlanService planService;

    @Resource
    private IPordWorkService workService;

    /**
     * 分页查询
     *
     * @return page
     */
    @GetMapping("list")
    public AjaxResult<PageResponseDto<ProPlanVO>> list(ProPlanQueryDto query) {
        PageResponseDto<ProPlanVO> result = planService.treeList(query);
        return AjaxResult.success(result);
    }

    /**
     * 拖轮计费左下方的全部数据总费用  TOTAL amount
     *
     * @return page
     */
    @GetMapping("totalAmount")
    @ApiOperation("拖轮计费-普通计费的全部数据总合计")
    public AjaxResult<String> totalAmount(ProPlanQueryDto query) {
        String totalAmount = planService.totalAmount(query);
        return AjaxResult.success(totalAmount);
    }

    /**
     * 根据ID查询
     *
     * @return ProPlanVO
     */
    @GetMapping("getById")
    public AjaxResult<ProPlanVO> getById(@RequestParam("id") Long id) {
        ProPlanVO detail = planService.detail(id);
        return AjaxResult.success(detail);
    }

    /**
     * 批量删除
     *
     * @return res
     */
    @PostMapping("removeBatch")
    @ApiOperation("批量删除作业计划")
    @RepeatSubmit
    public AjaxResult removeBatch(@RequestParam(name = "ids") String idList) {
        List<String> ids = Arrays.asList(idList.split(","));
        //只能删待审的,若选中的包含！=待审的，则ERROR
        long otherStatusCount = planService.count(new LambdaQueryWrapper<ProdPlan>()
                .ne(ProdPlan::getStatus, ProdPlanStatusConstant.WAIT_APPROVE)
                .in(ProdPlan::getId, ids));
        if (otherStatusCount > 0) {
            return AjaxResult.fail("只能删除待审核状态的数据");
        }
        planService.removeByIds(ids);
        //同时移除作业记录
        List<PordWork> workList = workService.list(new LambdaQueryWrapper<PordWork>().in(PordWork::getPlanId, ids));
        List<Long> patchIds = workList.stream().map(PordWork::getId).collect(Collectors.toList());
        workService.removeByIds(patchIds);
        return AjaxResult.success();
    }

    /**
     * 新增/修改
     *
     * @return res
     */
    @PostMapping("save")
    @ApiOperation("新增/修改作业计划")
    @RepeatSubmit
    public AjaxResult save(@RequestBody @Valid ProPlanSaveReqDto dto) {
        planService.saveOrUpdatePlan(dto);
        return AjaxResult.success();
    }

    /**
     * 批量修改(批量审)
     *
     * @return Plan
     */
    @PostMapping("approveBatch")
    @ApiOperation("批量审核/反审核作业计划")
    @RepeatSubmit
    public AjaxResult updateBatch(@RequestBody @Valid ProPlanApproveBatchReqDto dto) {
        planService.approveBatch(dto);
        return AjaxResult.success();
    }

    /**
     * 完工时调用，主要是为了算拖轮费用。 虽然设置的传入List,但其实只能传入一个对象。因为完工只能按条操作
     *
     * @param dtoList DataSource
     * @return result
     */
    @PostMapping("amountV2")
    @ApiOperation("拖轮计费")
    public AjaxResult updateTugAmount(@RequestBody @Valid List<TugCalculateFeeReqDto> dtoList) {
        planService.tugCalculateFee(dtoList);
        return AjaxResult.success();
    }

    @SneakyThrows
    @ApiOperation("作业计划导出")
    @GetMapping("/exportData")
    public void exportPlan(ProPlanQueryDto queryDto, HttpServletResponse response) {
        // 文件信息
        String fileName = "作业计划导出";

        // 查询要导出的数据
        List<ProPlanExportDto> exportDtoList = planService.exportPlanList(queryDto);

        ExcelWriter excelWriter = null;
        WriteSheet writeSheet;

        try {
            // 设置response
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 构建ExcelWriter
            excelWriter = EasyExcel.write(response.getOutputStream()).build();
            writeSheet = EasyExcel.writerSheet("sheet1").sheetNo(0).build();

            // 遍历 exportDtoList，生成表头和数据
            for (int i = 0; i < exportDtoList.size(); i++) {
                ProPlanExportDto plan = exportDtoList.get(i);

                // 一级表头（ProPlanExportDto 的字段）
                List<List<String>> planHeadList = new ArrayList<>();
                planHeadList.add(Lists.newArrayList("计划作业时间"));
                planHeadList.add(Lists.newArrayList("计划编号"));
                planHeadList.add(Lists.newArrayList("船名-航次"));
                planHeadList.add(Lists.newArrayList("泊位"));
                planHeadList.add(Lists.newArrayList("贸别"));
                planHeadList.add(Lists.newArrayList("进出"));
                planHeadList.add(Lists.newArrayList("装卸"));
                planHeadList.add(Lists.newArrayList("客户名称"));
                planHeadList.add(Lists.newArrayList("货名"));
                planHeadList.add(Lists.newArrayList("货重(吨)"));
                planHeadList.add(Lists.newArrayList("作业港区"));
                planHeadList.add(Lists.newArrayList("作业码头"));
                planHeadList.add(Lists.newArrayList("前吃水"));
                planHeadList.add(Lists.newArrayList("后吃水"));
                planHeadList.add(Lists.newArrayList("备注"));
                planHeadList.add(Lists.newArrayList("状态"));

                // 一级数据（ProPlanExportDto 的数据）
                List<List<String>> planData = new ArrayList<>();
                planData.add(Lists.newArrayList(
                        String.valueOf(plan.getPlanTime()),
                        plan.getPlanCode(),
                        plan.getShipName() + "-" + plan.getVoyage(),
                        plan.getBerthNo(),
                        Objects.requireNonNull(RateTradeTypeEnum.fromCode(plan.getTradeType())).getDesc(),
                        Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getInOut())).getDesc(),
                        Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getLoadUnload())).getDesc(),
                        plan.getCustomerName(),
                        plan.getCargoName(),
                        plan.getTon().toString(),
                        DictTypeEnum.PORT_AREA.getName(),
                        plan.getDockId() != null ? plan.getDockId().toString() : "",
                        plan.getFrontDraft() != null ? plan.getFrontDraft().toString() : "",
                        plan.getRearDraft() != null ? plan.getRearDraft().toString() : "",
                        plan.getRemark(),
                        plan.getStatus() != null ? Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getStatus().toString())).getDesc() : ""
                ));

                WriteTable planTable = EasyExcel.writerTable(2 * i)
                        .head(planHeadList)
                        .registerWriteHandler(new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle()))
                        .registerWriteHandler(new CustomCellWriteHeightConfig())
                        .registerWriteHandler(new CustomCellWriteWidthConfig())
                        .build();
                excelWriter.write(planData, writeSheet, planTable);

                // 二级表头（PordWorkExportDto 的字段）
                List<List<String>> workHeadList = new ArrayList<>();
                workHeadList.add(Lists.newArrayList("拖轮编号"));
                workHeadList.add(Lists.newArrayList("作业项目"));

                // 二级数据（PordWorkExportDto 的数据）
                List<List<String>> workData = new ArrayList<>();
                for (PordWorkExportDto work : plan.getChildren()) {
                    workData.add(Lists.newArrayList(work.getTugNo(), work.getWorkItemName()));
                }

                WriteTable workTable = EasyExcel.writerTable(2 * i + 1)
                        .head(workHeadList)
                        .registerWriteHandler(new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle()))
                        .registerWriteHandler(new CustomCellWriteHeightConfig())
                        .registerWriteHandler(new CustomCellWriteWidthConfig())
                        .build();
                excelWriter.write(workData, writeSheet, workTable);

                // 添加空行用于间隔
                List<List<String>> emptyRow = new ArrayList<>();
                emptyRow.add(Lists.newArrayList("", ""));
                excelWriter.write(emptyRow, writeSheet, workTable);
            }

        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }



    @SneakyThrows
    @ApiOperation("拖轮计费导出")
    @GetMapping("/exportTugFee")
    public void exportTugFee(ProPlanQueryDto queryDto, HttpServletResponse response) {
        // 文件信息
        String fileName = "拖轮计费导出";

        // 查询要导出的数据
        List<ProPlanExportDto> exportDtoList = planService.exportPlanList(queryDto);

        ExcelWriter excelWriter = null;
        WriteSheet writeSheet;

        try {
            // 设置response
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 构建ExcelWriter
            excelWriter = EasyExcel.write(response.getOutputStream()).build();
            writeSheet = EasyExcel.writerSheet("sheet1").sheetNo(0).build();

            // 遍历 exportDtoList，生成表头和数据
            for (int i = 0; i < exportDtoList.size(); i++) {
                ProPlanExportDto plan = exportDtoList.get(i);

                // 一级表头（ProPlanExportDto 的字段）
                List<List<String>> planHeadList = new ArrayList<>();
                planHeadList.add(Lists.newArrayList("计划作业时间"));
                planHeadList.add(Lists.newArrayList("计划编号"));
                planHeadList.add(Lists.newArrayList("船名-航次"));
                planHeadList.add(Lists.newArrayList("总费用"));
                planHeadList.add(Lists.newArrayList("费用备注"));
                planHeadList.add(Lists.newArrayList("泊位"));
                planHeadList.add(Lists.newArrayList("贸别"));
                planHeadList.add(Lists.newArrayList("进出"));
                planHeadList.add(Lists.newArrayList("装卸"));
                planHeadList.add(Lists.newArrayList("客户名称"));
                planHeadList.add(Lists.newArrayList("货名"));
                planHeadList.add(Lists.newArrayList("货重(吨)"));
                planHeadList.add(Lists.newArrayList("作业港区"));
                planHeadList.add(Lists.newArrayList("作业码头"));
                planHeadList.add(Lists.newArrayList("前吃水"));
                planHeadList.add(Lists.newArrayList("后吃水"));
                planHeadList.add(Lists.newArrayList("备注"));
                planHeadList.add(Lists.newArrayList("状态"));

                // 一级数据（ProPlanExportDto 的数据）
                List<List<String>> planData = new ArrayList<>();
                planData.add(Lists.newArrayList(
                        String.valueOf(plan.getPlanTime()),
                        plan.getPlanCode(),
                        plan.getShipName() + "-" + plan.getVoyage(),
                        plan.getFee() == null ? "" : plan.getFee().toString(),
                        plan.getCalculateRemark(),
                        plan.getBerthNo(),
                        Objects.requireNonNull(RateTradeTypeEnum.fromCode(plan.getTradeType())).getDesc(),
                        Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getInOut())).getDesc(),
                        Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getLoadUnload())).getDesc(),
                        plan.getCustomerName(),
                        plan.getCargoName(),
                        plan.getTon().toString(),
                        DictTypeEnum.PORT_AREA.getName(),
                        plan.getDockId() != null ? plan.getDockId().toString() : "",
                        plan.getFrontDraft() != null ? plan.getFrontDraft().toString() : "",
                        plan.getRearDraft() != null ? plan.getRearDraft().toString() : "",
                        plan.getRemark(),
                        plan.getStatus() != null ? Objects.requireNonNull(ProdPlanEnum.fromCode(plan.getStatus().toString())).getDesc() : ""
                ));

                WriteTable planTable = EasyExcel.writerTable(2 * i)
                        .head(planHeadList)
                        .registerWriteHandler(new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle()))
                        .registerWriteHandler(new CustomCellWriteHeightConfig())
                        .registerWriteHandler(new CustomCellWriteWidthConfig())
                        .build();
                excelWriter.write(planData, writeSheet, planTable);

                // 二级表头（PordWorkExportDto 的字段）
                List<List<String>> workHeadList = new ArrayList<>();
                workHeadList.add(Lists.newArrayList("拖轮编号"));
                workHeadList.add(Lists.newArrayList("作业项目"));
                workHeadList.add(Lists.newArrayList("费用"));
                workHeadList.add(Lists.newArrayList("费用备注"));
                workHeadList.add(Lists.newArrayList("开始作业时间"));
                workHeadList.add(Lists.newArrayList("结束作业时间"));
                workHeadList.add(Lists.newArrayList("作业时长(h)"));

                // 二级数据（PordWorkExportDto 的数据）
                List<List<String>> workData = new ArrayList<>();
                for (PordWorkExportDto work : plan.getChildren()) {
                    workData.add(Lists.newArrayList(
                            work.getTugNo(),
                            work.getWorkItemName(),
                            work.getAmount() == null ? "" : work.getAmount().toString(),
                            work.getCalculateRemark(),
                            DateUtils.localDateTime2Str(work.getBeginTime()),
                            DateUtils.localDateTime2Str(work.getEndTime()),
                            work.getWorkHours() == null ? "" : work.getWorkHours().toString()
                    ));
                }

                WriteTable workTable = EasyExcel.writerTable(2 * i + 1)
                        .head(workHeadList)
                        .registerWriteHandler(new HorizontalCellStyleStrategy(StyleUtils.getHeadStyle(), StyleUtils.getContentStyle()))
                        .registerWriteHandler(new CustomCellWriteHeightConfig())
                        .registerWriteHandler(new CustomCellWriteWidthConfig())
                        .build();
                excelWriter.write(workData, writeSheet, workTable);

                // 添加空行用于间隔
                List<List<String>> emptyRow = new ArrayList<>();
                emptyRow.add(Lists.newArrayList("", ""));
                excelWriter.write(emptyRow, writeSheet, workTable);
            }

        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }


}
